/*
 * Copyright 2009 Andreas Borglin andreas.borglin@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package borge.mobile.app.jakoon;

import borge.mobile.app.jakoon.SaveForm.SaveData;
import javax.microedition.midlet.MIDlet;
import org.eclipse.ercp.swt.mobile.MobileDevice;
import org.eclipse.ercp.swt.mobile.MobileShell;
import org.eclipse.ercp.swt.mobile.Screen;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;


/**
 * Main class. Handles MIDlet stuff and starts off execution.
 * This MIDlet uses eSWT as UI framework
 * 
 * @author Andreas Borglin
 */
public class Main extends MIDlet {

    // We only support 640x360 resolution phones
    public static final int SUPPORTED_LANDSCAPE_WIDTH = 640;
    public static final int SUPPORTED_LANDSCAPE_HEIGHT = 360;
    
    /** MIDlet entry point methods*/
    public void startApp(){ 
    
        // Start eSWT event thread
        Thread t = new ESwtExecutor();
        t.start();
    }
    
    public void pauseApp(){ }
    public void destroyApp(boolean b){ }
    /** END MIDlet entry point methods*/
    
    // eSWT specific below
    
    class ESwtExecutor extends Thread {
        
        private Display display;
        private MobileShell shell;
        private MobileDevice mobileDevice;
        private Screen screen;
        private Composite composite;
        private boolean exiting = false;
        
        private ImageForm imageForm;
        private SaveForm saveForm;
        //private UploadForm uploadForm;
        private ErrorForm errorForm;
        private ProgressForm progressForm;
        private ImageManipulatorForm manipulatorForm;
        private String defaultPath;        
        
        public void run(){
              
            initUI();
  
            String error = null;
            // Check if we have support on this platform
            if (!ImageForm.isPlatformSupported()) {
                error = "This phone does not have the necessary support!";
            }
            else if(!supportedResolution()){
                error = "This application only supports " +
                        SUPPORTED_LANDSCAPE_WIDTH + "x" + SUPPORTED_LANDSCAPE_HEIGHT +
                        " / " + SUPPORTED_LANDSCAPE_HEIGHT + "x" + SUPPORTED_LANDSCAPE_WIDTH +
                        " resolution phones";
            }
            
            if(error != null){
                MessageBox mb = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
                mb.setMessage(error);
                mb.open();
                exiting = true;
            }
            else{
                new StartupForm(this, composite);
            }
            
            // Enter event wait loop
            while (!exiting) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }

            // Clean up and destroy the MIDlet.
            display.dispose();
            notifyDestroyed();
        }
        
        protected void exit(){
            exiting = true;
            Display.getDefault().wake();
        }
        
        private boolean supportedResolution(){

            Rectangle bounds = screen.getBounds();
            if(screen.getOrientation() == Screen.LANDSCAPE){
                if(bounds.width == SUPPORTED_LANDSCAPE_WIDTH &&
                        bounds.height == SUPPORTED_LANDSCAPE_HEIGHT){
                    return true;
                }
            }
            else{ // Portrait mode
                if (bounds.height == SUPPORTED_LANDSCAPE_WIDTH &&
                        bounds.width == SUPPORTED_LANDSCAPE_HEIGHT) {
                    return true;
                }
            }

            return false;
            
        }
        
        protected void saveImage(SaveData saveData){
            imageForm.saveImage(saveData);
        }
        
        // Must be called from right thread
        private void internalUpdateProgress(int step, int totsteps, String text){
            progressForm.initProgress(totsteps);
            progressForm.update(step, text);
        }
        
        // Must be in eSWT thread to modify UI stuff
        protected void updateProgress(int step, int totsteps, String text, String errorMsg) {
            display.syncExec(new ProgressConsumer(step, totsteps, text, errorMsg));
        }
        
        protected void progressDone(String text, String errorMsg){
            progressForm.done(text, errorMsg);
        }
        
        protected void loadImageForm(boolean startOver){
            
            if(imageForm == null)
                imageForm = new ImageForm(this, composite);
            else
                imageForm.makeVisible(startOver);
            
            composite.layout();
        }
        
        protected void loadSaveForm(String dir, String file, String[] formats){
            
            if(saveForm == null)
                saveForm = new SaveForm(this, composite);
            else
                saveForm.makeVisible();
            
            saveForm.setDirAndFile(dir, file);
            saveForm.setOutputFormats(formats);
            
            composite.layout();
        }

        protected void loadImageManipulatorForm(Image image, String[] wblist){

            if(manipulatorForm == null)
                manipulatorForm = new ImageManipulatorForm(this, composite, imageForm);
            else
                manipulatorForm.makeVisible();

            if(image != null)
                manipulatorForm.setImage(image);

            if(wblist != null)
                manipulatorForm.setWhitebalanceList(wblist);

            composite.layout();
        }
        
        protected void loadProgressForm(int totalSteps){
            
            if(progressForm == null)
                progressForm = new ProgressForm(this, composite);
            else
                progressForm.setVisible(true);
            
            if(totalSteps != -1)
                progressForm.initProgress(totalSteps);
            
            composite.layout();
        }
        
        protected void loadUploadForm(){
            MessageBox mb = new MessageBox(shell, SWT.ICON_INFORMATION);
            mb.setMessage("Upload is not implemented yet");
            mb.open();
            
            loadImageForm(false);
        }
        
        protected void loadErrorForm(String error){
            if(errorForm == null)
                errorForm = new ErrorForm(this, composite);
            else
                errorForm.setVisible(true);
            
            errorForm.setError(error);
            
            composite.layout();
        }
        
        private void initUI(){
    
            display = new Display();
            shell = new MobileShell(display);

            shell.setFullScreenMode(true);
            shell.open();

            // shell layout
            GridLayout layout = new GridLayout();
            
            // Zero the margins that are non-zero by default
            // We want shell to cover the whole screen
            layout.horizontalSpacing = 0;
            layout.verticalSpacing = 0;
            layout.marginWidth = 0;
            layout.marginHeight = 0;
            shell.setLayout(layout);

            mobileDevice = MobileDevice.getMobileDevice();
            Screen[] screens = mobileDevice.getScreens();
            screen = screens[0];
            screen.setOrientation(Screen.LANDSCAPE);
            
            createComposite();
            
        }
        
        private void createComposite(){
            
            if(composite != null){
                composite.setVisible(false);
                composite.dispose();
            }
            
            // composite is our top container that covers the whole shell
            composite = new Composite(shell, SWT.NONE);
            composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

            FormLayout flayout = new FormLayout();
            composite.setLayout(flayout);

            shell.layout();
        }
        
        protected Screen getScreen(){
            return screen;
        }
        
        protected Display getDisplay(){
            return display;
        }
        
        protected Shell getShell(){
            return shell;
        }

        /**
         * @return the defaultPath
         */
        public String getDefaultPath() {
            return defaultPath;
        }

        /**
         * @param defaultPath the defaultPath to set
         */
        public void setDefaultPath(String defaultPath) {
            this.defaultPath = defaultPath;
            RMSHandler.setDefaultPath(defaultPath);
        }
        
        class ProgressConsumer implements Runnable {

            private int curStep;
            private int totSteps;
            private String stepText;
            private String errorMsg;

            public ProgressConsumer(int curStep, int totSteps, String stepText, String errorMsg) {
                this.curStep = curStep;
                this.totSteps = totSteps;
                this.stepText = stepText;
                this.errorMsg = errorMsg;
            }

            public void run() {
                
                // If taskFinished has been called
                // TODO: This is a rather stupid way of doing it..
                if(stepText.equals("true") || stepText.equals("false")){
                    progressDone(stepText, errorMsg);
                }
                else
                    internalUpdateProgress(curStep, totSteps, stepText);

            }
        }
    }
}
